/* 
 * DA4.cpp 
 * 
 * Created: 3/24/2014 2:03:40 PM 
 *  Author: Jared 
 *  
 *  C program to generate three PWM signals to drive a RGB LED using TIMER 0 of the AVR-Atmega328P.  
 * The program changes the period and duty cycle of the PWMs every second to display a varying range 
 * of colors and brightness to the LED. 
 */ 
     
     
#define F_CPU 1000000     // XTAL = 1MHz  
#include <avr/io.h> 
#include <util/delay.h> 
    
void AdjustLevels(uint8_t, uint8_t, int, int, int); 
    
int main(void) 
{ 
    DDRB = 0x08;                //  Enable OC2A  (PB3 -> 2^3 = 8) 
    PORTB = 0x00;               //  Set Output high - turn all LEDs off 
    DDRD = 0x60;                //  Enable OC0A / OC0B  (PD6/PD5 -> 2^6 + 2^5 = 96 = 0x60) 
    PORTD = 0x00;               //  Set Output high - turn all LEDs off 
        
// Initialize Timer0/2 
// Phase-Correct PWM Mode (8-bit), Set OC0A, OC0B, OC2A on compare 
// (1 << WGMx0) = Phase-Correct PWM, (1 << COMxN1, COMxN0) = Set Output(OCRxN) registers on compare 
    TCCR0A |= ( 1 << COM0A1 ) | ( 1 << COM0A0 ) | ( 1 << COM0B1 ) | ( 1 << COM0B0) | ( 1 << WGM00 );   
    TCCR2A |= ( 1 << COM2A1 ) | ( 1 << COM2A0 ) | ( 1 << WGM20 ); 
        
    
    while(1) 
    { 
    // Prescaler Timer0: 1, Prescaler Timer2: 1024, Duty Cycles: 10%, 30%, 50% 
        AdjustLevels(0x9, 0xD, 26, 77, 128); 
        _delay_ms(500);        // wait 1 second 
    // Prescaler Timer0: 8, Prescaler Timer2: 64, Duty Cycles: 20%, 50%, 70%     
        AdjustLevels(0xA, 0xB, 51, 128, 179); 
        _delay_ms(500); 
    // Prescaler Timer0: 64, Prescaler Timer2: 256, Duty Cycles: 30%, 60%, 90%   
        AdjustLevels(0xB, 0xC, 77, 154, 230); 
        _delay_ms(500); 
    // Prescaler Timer0: 256, Prescaler Timer2: 1, Duty Cycles: 70%, 30%, 50%    
        AdjustLevels(0xC, 0x9, 179, 77, 128); 
        _delay_ms(500); 
    // Prescaler Timer0: 1024, Prescaler Timer2: 8, Duty Cycles: 80%, 60%, 50%   
        AdjustLevels(0xD, 0xA, 205, 154, 128); 
        _delay_ms(500); 
    } 
} 
    
//************************* 
//  Function to adjust the period of the pwm signals by changing the Prescaler for Timers 0/2, which  
//  changes the color of the RGB LED. 
//  Also adjusts the duty cycles for pwm 1,2,3, which changes the brightness of the RGB LED. 
    
void AdjustLevels(uint8_t pre0, uint8_t pre2, int pwm1, int pwm2, int pwm3){ 
    TCCR0B = pre0;                  // TCCR0B |= ( 1 << WGM02 ) | (CS2:CS0) 
    TCCR2B = pre2;                  // TCCR2B |= ( 1 << WGM22 ) | (CS2:CS0) 
    while (pwm1 != 255) 
    { 
        OCR0A = pwm1;                  // OCRx = duty cycle(decimal) * 256 
        _delay_ms(25); 
        pwm1++; 
    } 
    while (pwm3 != 255) 
    { 
        OCR2A = pwm3; 
        _delay_ms(25); 
        pwm3++; 
    } 
    while (pwm2 != 255) 
    {                      
        OCR0B = pwm2; 
        _delay_ms(25); 
        pwm2++; 
    } 
}